//在这个文件里实现对文本节点 和 元素节点指令编译 例如：v-text v-model
class Compiler {
	constructor(vm) {
		//拿到vm实例
		this.vm = vm
		//拿到el
		this.el = vm.$el
		//编译模板
		this.compile(this.el)
	}
	//编译模板
	compile(el) {
		//获取子节点 伪数组 转为真的数组
		let childNodes = [...el.childNodes]
		// 循环遍历
		childNodes.forEach(node => {
			//根据不同的节点进行编译
			if (node.nodeType === 3) { //文本节点
				this.compileText(node)
			} else if (node.nodeType === 1) { //元素节点
				this.compileElement(node)
			}
			//判断是否存在于节点 考虑递归
			if (node.childNodes && node.childNodes.length) {
				// 继续递归编译模板
				this.compile(node)
			}
		});
	}
	//编译文本节点  正则匹配出{{}}中的变量 并且给替换成值
	compileText(node) {
		//正则匹配
		let reg = /\{\{(.+?)\}\}/
		//获取节点文本内容
		let content = node.textContent
		//判断是否有插值
		if (reg.test(content)) {
			//获取分组匹配 $1
			let key = RegExp.$1.trim()
			//赋值替换
			node.textContent = content.replace(reg, this.vm[key])
			//创建者观察者
			new Watcher(this.vm, key, (newValue) => {
				node.textContent = newValue
			})
		}
	}
	//编译元素节点 匹配v-相关内容
	compileElement(node) {
		//获取元素 遍历元素上的所有属性
		let attr = [...node.attributes] || []
		attr.forEach((attrItem) => {
			//获取属性名
			let attrName = attrItem.name
			//判断是否是V-开头指令
			if (attrName.startsWith('v-')) {
				//获取attrname
				attrName = attrName.substr(2)
				//获取当前绑定属性值
				let key = attrItem.value
				//指令操作  执行更新方法
				this.update(node, key, attrName)
			}
		})
	}
	//添加更新指令方法
	update(node, key, attrName) {
		//根据不同的v-绑定值 执行不同的方法
		let updateFn = this[attrName + 'Updater']
		updateFn && updateFn.call(this, node, key, this.vm[key])
	}
	//添加更新方法 v-text
	textUpdater(node, key, value) {
		node.textContent = value
		//创建者观察者
		new Watcher(this.vm, key, newValue => {
			node.textContent = newValue
		})
	}
	//v-model
	modelUpdater(node, key, value) {
		node.value = value
		//创建者观察者
		new Watcher(this.vm, key, newValue => {
			node.value = newValue
		})
		//实现双向绑定 监听input事件  修改data中属性
		node.addEventListener('input',()=>{
			this.vm[key] = node.value
		})
	}
}
